package com.bjy.qa.agent.tools;

import com.bjy.qa.agent.interceptor.InterceptorConf;
import com.bjy.qa.agent.tools.juel.JuelConf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.*;

/**
 * 环境检查工具类
 */
@Component
public class EnvCheckTool {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public static String javaPath = "unknown \n"; // 全局环境变量的JAVA_HOME
    public static String javaVersion = "unknown \n"; // 运行时的Java Version
    public static String system; // 运行时的系统
    public static String hostAddress = "unknown"; // 本机 ip 地址
    public static String mockBaseURL = "unknown"; // mock base 地址

    public static String appVersion; // Agent 版本号（spring.application.version）

    public static String pythonCommand = ""; // python 运行命令（路径+命令）

    @Value("${spring.application.version}")
    public void setAppVersion(String version) {
        this.appVersion = version;
    }

    @Value("${qap.python.command:python3}")
    public void setPythonCommand(String cmd) {
        this.pythonCommand = cmd;
    }

    static {
        system = System.getProperty("os.name").toLowerCase();
        hostAddress = getHostAddress();
    }

    /**
     * 获取本机 ip 地址
     * @return
     */
    private static String getHostAddress() {
        String hostaddress;
        // 使用 InetAddress 获取本机 ip 地址
        try {
            hostaddress = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            hostaddress = "127.0.0.1"; // 无法解析系统主机名，使用默认值
        }

        // 如果 InetAddress 获取的是 127.0.0.1，使用 NetworkInterface 重新获取 ip
        if ("127.0.0.1".equals(hostaddress)) {
            try {
                Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
                while (netInterfaces.hasMoreElements()) {
                    NetworkInterface ni = netInterfaces.nextElement();
                    Enumeration<InetAddress> ips = ni.getInetAddresses();
                    while (ips.hasMoreElements()) {
                        InetAddress ip = ips.nextElement();
                        if (ip.isSiteLocalAddress()) {
                            hostaddress = ip.getHostAddress();
                        }
                    }
                }
            } catch (Exception e) {
                hostaddress = "127.0.0.1"; // 使用 NetworkInterface 获取 ip 失败，使用默认值
            }
        }
        return hostaddress;
    }

    @Bean
    public boolean checkEnv(ConfigurableApplicationContext context) {
        logger.info("========================== 环境检查 - 开始 ==========================");
        try {
            checkDirectoryFile();
            checkJava();
            checkPython();
        } catch (Exception e) {
            logger.info("========================== 环境检查 - 完成 ==========================");
            context.close();
            System.exit(0);
        }
        logger.info("======================== 环境检查 - 检查结果 =========================");
        this.printPass(); // 环境检查通过后打印的信息
        logger.info("========================== 环境检查 - 完成 ==========================");

        // 获取 mockBaseURL
        Environment environment = SpringTool.getBean(Environment.class);
        if (environment.getProperty("server.ssl.enabled") == null) {
            mockBaseURL = "http://" + hostAddress + ":" + environment.getProperty("server.port") + "/mock/前置url/";
        } else {
            mockBaseURL = "https://" + hostAddress + ":" + environment.getProperty("server.port") + "/mock/前置url/";
        }

        this.printConfInfo(); // 打印配置信息
        return true;
    }

    /**
     * 检查java环境
     */
    private void checkJava() {
        String type = "Check JAVA";
        javaPath = System.getenv("JAVA_HOME");
        javaVersion = System.getProperty("java.version");
        if (!StringUtils.hasText(javaPath)) {
            logger.error("系统变量【JAVA_HOME】返回值为空！");
            logger.error(getPrintFail(type + "_HOME"));
            logger.error(getPrintInfo("提示：可前往 https://www.oracle.com/java/technologies/downloads/ 下载 jdk 并设置 JAVA_HOME 系统变量"));
            throw new RuntimeException();
        }
        if (Integer.valueOf(javaVersion.split("\\.")[0]) > 15) {
            // 检查必须的 Java 启动参数
            boolean javaPass = false;
            RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            List<String> jvmArgs = runtimeMXBean.getInputArguments();
            for (String jvmArg : jvmArgs) {
                if (jvmArg.indexOf("--add-opens=java.base/java.lang=ALL-UNNAMED") >= 0) {
                    javaPass = true;
                }
            }
            if (!javaPass) {
                logger.error("【JAVA_VERSION】版本过高 或 JAVA启动参数错误！");
                logger.error(getPrintFail(type + "_VERSION"));
                logger.error(getPrintInfo("提示："));
                logger.error(getPrintInfo("1、可前往 https://www.oracle.com/java/technologies/downloads/ 或 https://docs.aws.amazon.com/corretto/latest/corretto-15-ug/downloads-list.html 下载jdk并设置JAVA_HOME系统变量"));
                logger.error(getPrintInfo("2、添加JAVA启动参数 --add-opens=java.base/java.lang=ALL-UNNAMED，例如：java --add-opens=java.base/java.lang=ALL-UNNAMED -jar qap.jar"));
                throw new RuntimeException();
            }
        }
        logger.info(getPrintPass(type));
    }

    /**
     * 检查 python 环境
     */
    private void checkPython() {
        String type = "Check Python";

        String result = ProcessCommandTool.getProcessLocalCommandStr(String.format(pythonCommand +  " -V"));
        if (!result.toLowerCase().contains("python 3.")) { // 不是 python 3
            logger.error("【Python】版本过低 或 Python 未安装！");
            logger.error(getPrintFail(type));
            logger.error(getPrintInfo("提示："));
            logger.error(getPrintInfo("1、虽然 Python 环境检查失败，但不会阻断 agent 启动。当运行自定义 Python 脚本时，会提示对应失败信息"));
            logger.error(getPrintInfo("2、没安装 python3，请安装"));
            logger.error(getPrintInfo("3、已安装 python3，请打开 application.yml ，将 qap.python.command 对应的内容修改为 python3 的 路径+命令"));
            logger.error(getPrintInfo("3、已安装 python3，也可以在 path 中添加 python3 路径 或 添加 python3 别名"));
            pythonCommand = "";
        } else { // 是 python 3
            logger.info(getPrintPass(type));
        }
    }

    /**
     * 检查目录和文件
     */
    private void checkDirectoryFile() {
        String type = "Check Directory / File";
        String home = System.getProperty("user.dir");

        File testOutputDir = new File("test-output");
        if (testOutputDir.exists()) {
            if (!testOutputDir.isDirectory()) {
                logger.error("日志目录 test-output 检测失败，当前 test-output 是文件而非目录！");
                logger.error(getPrintFail(type));
                logger.error(getPrintInfo("提示：可进入 " + home + " 目录，手动删除 test-output 文件后重新启动 agent"));
                throw new RuntimeException();
            }
        } else {
            testOutputDir.mkdirs();
        }
        logger.info(getPrintPass(type));
    }

    private String getPrintPass(String s) {
        if (system.contains("win")) {
            return ("→ " + s + " Pass √");
        } else {
            return ("\33[32;1m👉 " + s + " Pass ✔\033[0m");
        }
    }

    public String getPrintInfo(String s) {
        if (system.contains("win")) {
            return "· " + s;
        } else {
            return "\33[34;1m" + s + "\033[0m";
        }
    }

    private String getPrintFail(String s) {
        if (system.contains("win")) {
            return ("→ " + s + " Fail ×");
        } else {
            return ("\33[31;1m👉 " + s + " Fail ❌\033[0m");
        }
    }

    /**
     * 环境检查通过后打印的信息
     */
    private void printPass() {
        logger.info(getPrintInfo("JAVA_HOME: ") + javaPath);
        logger.info(getPrintInfo("java version: ") + javaVersion);
        logger.info(getPrintInfo("System: ") + system);
    }

    /**
     * 打印配置信息
     */
    private void printConfInfo() {
        logger.info("======================== 配置信息打印 - 开始 =========================");

        JuelConf juelConf = SpringTool.getBean(JuelConf.class); // 获得 Juel 配置
        logger.info(getPrintInfo("Juel 配置信息 - 随机字符串: ") + juelConf.getStrChar());
        logger.info(getPrintInfo("Juel 配置信息 - 随机特殊字符串: ") + juelConf.getSpecialChar());

        InterceptorConf interceptorConf = SpringTool.getBean(InterceptorConf.class); // 获得 拦截器 配置
        logger.info(getPrintInfo("前置拦截器 - 接口: ") + Arrays.toString(interceptorConf.getTesterBeforeInterceptors()));
        logger.info(getPrintInfo("后置拦截器 - 接口: ") + Arrays.toString(interceptorConf.getTesterAfterInterceptors()));
        logger.info(getPrintInfo("前置拦截器 - 性能: ") + Arrays.toString(interceptorConf.getPerfBeforeInterceptors()));

        logger.info("======================== 配置信息打印 - 完成 =========================");
    }
}